export default class BubbleUtil
{
    private static offsetX:number =  -360;
    private static offsetY:number = 0;
    private static diameter: number = 65.4;
    private static radius: number = 32.7;
    /**
     * 返回世界坐标系中的坐标
     * @param row 
     * @param col 
     * @param height 
     */
    public static getPosByRowAndCol(row, col, height): cc.Vec2 
    {  
        let posX, posY;   
        let flipRow = height - row - 1;
        posX = col * 2 * this.radius + this.radius + (row % 2) * this.radius;
        posY = flipRow * 2 * this.radius * Math.sin(Math.PI/3) + this.radius;

        posX += this.offsetX;
        posY += this.offsetY;

        return cc.v2(posX, posY);
    }
    /**
     * 
     * @param x 世界坐标系中的坐标
     * @param y 世界坐标系中的坐标
     * @param height 
     */
    public static getRowAndColByPos(x, y, height): cc.Vec2 
    {  
        let newX = x - this.offsetX;
        let newY = y - this.offsetY;
        let row, col, flipRow;
        flipRow = newY / (2 * this.radius * Math.sin(Math.PI/3));
        row = height - Math.floor(flipRow) - 1;
        col = (newX - (row % 2) * this.radius) / (2 * this.radius);
        col = Math.floor(col);


        // 落入外切矩形，需要特殊处理一下。落入左下角和右下角，row和col需要重新调整
        let pos = this.getPosByRowAndCol(row, col, height);
        let len = Math.sqrt((x - pos.x)*(x - pos.x) + (y - pos.y) * (y - pos.y));
        // 落入左下角/右下角
        if(len >= this.radius && y < pos.y)
        {
            cc.log("BubbleUtil|getRowAndColByPos|---1---" + row + "," + col)

            // 左下角
            if(x < pos.x)
            {
                col = col -1 + row % 2;
            }
            else if(x > pos.x) // 右下角
            {
                col = col + row % 2;
            }
            row = row + 1;
            cc.log("BubbleUtil|getRowAndColByPos|---2---" + row + "," + col)
        }

        return cc.v2(row, col);
    }

    // 检查点击的x,y坐标计算出的row和col是否有效
    public static checkPointValid(x, y, row, col, height): boolean
    {
        if(row % 2 != 0 && col >= 10)
        {
            return false;
        }
        // 落入外切矩形，也算检查通过
        // let pos = this.getPosByRowAndCol(row, col, height);
        // let len = Math.sqrt((x - pos.x)*(x - pos.x) + (y - pos.y) * (y - pos.y));
        // if(len > this.radius)
        // {
        //     return false;
        // }
        return true;
    }

    public static touchPointTransform(pos:cc.Vec2): cc.Vec2
    {
        pos.x -= 360;
        pos.y -= 640;
        return pos;
    }

    public static isCollisionRaw(pos1:cc.Vec2, pos2:cc.Vec2): boolean
    {
        let result = false;
        let len = Math.sqrt((pos1.x - pos2.x)*(pos1.x - pos2.x) + (pos1.y - pos2.y) * (pos1.y - pos2.y));
        cc.log("BubbleUtil|isCollisionRaw|len=" + len);
        if(len <= BubbleUtil.diameter)
        {
            result = true;
        }
        return result;
    }

    /**
     * bubble ball在调整位置后可能有碰撞，但是在原始路径上可能还没有相撞
     * @param bubbleMap 
     * @param row 
     * @param col 
     */
    public static isCollision(bubbleMap:string[][], row, col, realPos:cc.Vec2): boolean
    {
        if(row < 0 || row > bubbleMap.length || col < 0 || col > (row+1) % 2 + 10)
        {
            return false;
        }
        
        let offsetCol = row % 2 == 0 ? col  -1: col;

        if(row - 1 >= 0)
        {
            if(offsetCol < bubbleMap[row-1].length && bubbleMap[row-1][offsetCol] != null)
            {
                if(BubbleUtil.isCollisionRaw(bubbleMap[row-1][offsetCol].getPosition(), realPos)) return true;
            }
            if(offsetCol + 1 < bubbleMap[row-1].length && bubbleMap[row-1][offsetCol+1] != null)
            {
               if(BubbleUtil.isCollisionRaw(bubbleMap[row-1][offsetCol+1].getPosition(), realPos)) return true;
            }
        }

        if(row < bubbleMap.length)
        {
            if(col -1 >= 0 && bubbleMap[row][col-1] != null)
            {
                if(BubbleUtil.isCollisionRaw(bubbleMap[row][col-1].getPosition(), realPos)) return true;
            }
            if(col + 1 < bubbleMap[row].length && bubbleMap[row][col+1] != null)
            {
                if(BubbleUtil.isCollisionRaw(bubbleMap[row][col+1].getPosition(), realPos)) return true;
            }
        }

        if(row + 1 < bubbleMap.length)
        { 
            if(offsetCol < bubbleMap[row+1].length && bubbleMap[row+1][offsetCol] != null)
            {
                if(BubbleUtil.isCollisionRaw(bubbleMap[row+1][offsetCol].getPosition(), realPos)) return true;
            }
            if(offsetCol + 1 < bubbleMap[row].length && bubbleMap[row+1][offsetCol+1] != null)
            {
                if(BubbleUtil.isCollisionRaw(bubbleMap[row+1][offsetCol+1].getPosition(), realPos)) return true;
            }
        }

        return false;
    }

    public static bfsFindTypeNodes(originNode, bubbleMap:cc.Node[][]): cc.Node[]
    {
        let originBubble = originNode.getComponent("Bubble");
        let nodes:cc.Node[] = [];
        let row = originBubble.row;
        let col = originBubble.col;
        let type = originBubble.type;

        if(row < 0 || row > bubbleMap.length || col < 0 || col > (row+1) % 2 + 10)
        {
            return nodes;
        }
        
        let offsetCol = row % 2 == 0 ? col  -1: col;

        if(row - 1 >= 0)
        {
            if(offsetCol < bubbleMap[row-1].length && bubbleMap[row-1][offsetCol] != null)
            {
                let tmpNode = bubbleMap[row-1][offsetCol];
                if(tmpNode.getComponent("Bubble").type == type)
                {
                    nodes.push(tmpNode);
                }
            }
            if(offsetCol + 1 < bubbleMap[row-1].length && bubbleMap[row-1][offsetCol+1] != null)
            {
                let tmpNode = bubbleMap[row-1][offsetCol+1];
                if(tmpNode.getComponent("Bubble").type == type)
                {
                    nodes.push(tmpNode);
                }
            }
        }

        if(row < bubbleMap.length)
        {
            if(col -1 >= 0 && bubbleMap[row][col-1] != null)
            {
                let tmpNode = bubbleMap[row][col-1];
                if(tmpNode.getComponent("Bubble").type == type)
                {
                    nodes.push(tmpNode);
                }
            }
            if(col + 1 < bubbleMap[row].length && bubbleMap[row][col+1] != null)
            {
                let tmpNode = bubbleMap[row][col+1];
                if(tmpNode.getComponent("Bubble").type == type)
                {
                    nodes.push(tmpNode);
                }
            }
        }

        if(row + 1 < bubbleMap.length)
        { 
            if(offsetCol < bubbleMap[row+1].length && bubbleMap[row+1][offsetCol] != null)
            {
                let tmpNode = bubbleMap[row+1][offsetCol];
                if(tmpNode.getComponent("Bubble").type == type)
                {
                    nodes.push(tmpNode);
                }
            }
            if(offsetCol + 1 < bubbleMap[row].length && bubbleMap[row+1][offsetCol+1] != null)
            {
                let tmpNode = bubbleMap[row+1][offsetCol+1];
                if(tmpNode.getComponent("Bubble").type == type)
                {
                    nodes.push(tmpNode);
                }
            }
        }

        return nodes;
    }

    public static triggerNode(bubbleNode:cc.Node, bubbleMap:cc.Node[][]): cc.Node[]
    {
        let joinNodes:cc.Node[] = [];
        let bfsQueue:cc.Node[] = [];

        joinNodes.push(bubbleNode);
        bfsQueue.push(bubbleNode);

        bubbleNode.getComponent("Bubble").isBfsVisit = true;

        /**
         * 按照广度优先遍历寻找符合要求的结点
         */
        for(let bfsLevel = 0; bfsQueue.length > 0; bfsLevel++)
        {
            // 存储下一层的结点
            let nextLevelNodes = [];
            // 寻找以本层结点为中心的结点
            while(bfsQueue.length > 0)
            {
                let item = bfsQueue.pop();
                item.getComponent("Bubble").bfsLevel = bfsLevel;

                let nodes = BubbleUtil.bfsFindTypeNodes(item, bubbleMap);
                // 过滤掉已经访问过的
                nodes.filter(newNode=>{
                    return !newNode.getComponent("Bubble").isBfsVisit;
                }).forEach(newNode=>{
                    newNode.getComponent("Bubble").isBfsVisit = true;
                    nextLevelNodes.push(newNode);
                    joinNodes.push(newNode);
                });
            }

            bfsQueue = nextLevelNodes;
        }


        // 查找完毕，重置访问标识
        joinNodes.forEach(node=>{
            node.getComponent("Bubble").isBfsVisit = false;
        });
        
        return joinNodes;
    }

    public static judgeCancelFire(normalVec:cc.Vec2): boolean
    {
        let result = false;
        let cancelAngle = 0.268; // tan15
        if(Math.abs(normalVec.y / normalVec.x) < cancelAngle)
        {
            result = true;
        }
        return result;
    }
}
